package com.example.elysiumease;

import com.example.elysiumease.handler.WKTConverter;
import com.example.elysiumease.mapper.ZoneMapper;
import com.example.elysiumease.model.Zone;
import com.example.elysiumease.model.Zone.ZoneType;
import org.junit.jupiter.api.Test;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.io.ParseException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Commit;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Transactional
@Commit
public class ZoneMapperTest {

    private final GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326);

    @Autowired
    private ZoneMapper zoneMapper;

    private Zone createTestZone() {
        Zone zone = new Zone();
        zone.setZoneName("TestZone_" + System.currentTimeMillis());
        zone.setZoneType(ZoneType.HEAVEN);
        zone.setCapacity(1000);
        zone.setCurrentPopulation(200);
        zone.setDescription("Test zone");
        
        // 设置标准坐标点
        Coordinate coord = new Coordinate(116.404, 39.915);
        zone.setCoordinates(geometryFactory.createPoint(coord));
        return zone;
    }

    @Test
    void testInsertZoneWithCoordinates() {
        Zone zone = createTestZone();

        int result = zoneMapper.insert(zone);
        assertEquals(1, result);
        assertNotNull(zone.getZoneId(), "插入后应生成区域ID");

        Zone dbZone = zoneMapper.selectById(zone.getZoneId());
        assertNotNull(dbZone.getCoordinates(), "坐标数据不应为空");
        assertEquals(116.404, dbZone.getCoordinates().getX(), 0.001, "经度精度验证");
        assertEquals(39.915, dbZone.getCoordinates().getY(), 0.001, "纬度精度验证");
    }

    @Test
    void testUpdateZoneCapacity() {
        Zone zone = createTestZone();
        zoneMapper.insert(zone);

        // 修改容量和人口
        zone.setCapacity(2000);
        zone.setCurrentPopulation(500);
        zoneMapper.update(zone);

        Zone updatedZone = zoneMapper.selectById(zone.getZoneId());
        assertAll("容量相关字段验证",
                () -> assertEquals(2000, updatedZone.getCapacity()),
                () -> assertEquals(500, updatedZone.getCurrentPopulation())
        );
    }

    @Test
    void testDeleteZone() {
        Zone zone = createTestZone();
        zoneMapper.insert(zone);
        
        // 添加坐标验证确保插入成功
        Zone insertedZone = zoneMapper.selectById(zone.getZoneId());
        assertNotNull(insertedZone.getCoordinates(), "坐标必须存在");
        
        int deleteResult = zoneMapper.deleteById(zone.getZoneId());
        assertEquals(1, deleteResult);
        assertNull(zoneMapper.selectById(zone.getZoneId()), "删除后查询应返回null");
    }

    @Test
    void testUniqueZoneNameConstraint() {
        String uniqueName = "Unique_Zone_" + System.currentTimeMillis();

        // 创建第一个区域
        Zone zone1 = createTestZone();
        zone1.setZoneName(uniqueName); // 分开设置属性
        zoneMapper.insert(zone1);

        // 创建第二个同名区域
        Zone zone2 = createTestZone();
        zone2.setZoneName(uniqueName); // 分开设置属性

        Exception ex = assertThrows(Exception.class, () -> zoneMapper.insert(zone2));
        assertTrue(ex.getMessage().contains("Duplicate entry"), "应触发唯一约束异常");
    }



    @Test
    void testInsertWithCorrectWKT() {
        Zone zone = createTestZone();

        int result = zoneMapper.insert(zone);
        assertEquals(1, result);
        assertNotNull(zone.getZoneId(), "插入后应生成区域ID");

        Zone dbZone = zoneMapper.selectById(zone.getZoneId());
        assertNotNull(dbZone, "查询结果不应为null");
        assertNotNull(dbZone.getCoordinates(), "坐标数据不应为空");
        assertEquals(116.404, dbZone.getCoordinates().getX(), 0.001, "经度精度验证");
        assertEquals(39.915, dbZone.getCoordinates().getY(), 0.001, "纬度精度验证");
    }

    @Test
    void testZoneTypeEnumMapping() {
        Zone zone = createTestZone();
        zone.setZoneType(ZoneType.HELL); // 分开设置属性
        zoneMapper.insert(zone);

        Zone dbZone = zoneMapper.selectById(zone.getZoneId());
        assertEquals(ZoneType.HELL, dbZone.getZoneType(), "区域类型应正确映射");
    }

    @Test
    void testCoordinatePrecision() {
        // 创建基础对象
        Zone zone = createTestZone();

        // 分步设置属性
        Point precisePoint = geometryFactory.createPoint(new Coordinate(116.397389, 39.909736));
        zone.setCoordinates(precisePoint);
        zone.setZoneName("Precision_Test_Zone");

        // 执行数据库操作
        zoneMapper.insert(zone);

        // 验证结果
        Zone dbZone = zoneMapper.selectById(zone.getZoneId());
        assertAll("坐标精度验证",
                () -> assertEquals(116.397389, dbZone.getCoordinates().getX(), 0.000001),
                () -> assertEquals(39.909736, dbZone.getCoordinates().getY(), 0.000001)
        );
    }

    @Test
    void testCoordinateStoragePrecision() {
        // 创建高精度坐标
        Coordinate preciseCoord = new Coordinate(116.397389, 39.909736);
        Zone zone = createTestZone();
        zone.setCoordinates(geometryFactory.createPoint(preciseCoord));
        zone.setZoneName("HighPrecisionTest");

        zoneMapper.insert(zone);
        
        Zone dbZone = zoneMapper.selectById(zone.getZoneId());
        assertAll("坐标存储验证",
            () -> assertEquals(preciseCoord.x, dbZone.getCoordinates().getX(), 0.000001),
            () -> assertEquals(preciseCoord.y, dbZone.getCoordinates().getY(), 0.000001)
        );
    }

    @Test
    void testBatchOperations() {
        // 批量插入测试
        List<Zone> zones = IntStream.range(0, 5)
            .mapToObj(i -> {
                Zone z = createTestZone();
                z.setZoneName("BatchTest_" + i);
                return z;
            }).collect(Collectors.toList());

        zones.forEach(zoneMapper::insert);
        
        // 验证批量删除
        int deleted = zones.stream()
            .mapToInt(z -> zoneMapper.deleteById(z.getZoneId()))
            .sum();
        assertEquals(5, deleted, "应删除5条记录");
    }
}